;;; Copyright (c) 1999 Massachusetts Institute of Technology
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, see https://gnu.org/licenses or
;;; write to:
;;;  Free Software Foundatiom, Inc.
;;;  51 Franklin St, Fifth Floor
;;;  Boston, MA 02110-1301
;;;  USA

;********************************
;**
;** TO BE DONE:
;**
;** RECORDS LONGER THAN 1K
;** AUTOMTAIC DETERMINATION OF DENSITY AND RECORD LENGTH WHEN READING
;** ALLOW CLOSE WHEN TAPE HAS BEEN TAKEN OFF
;** BE MORE FORGIVING OF CONTROLLER LOSSAGE
;** PASS .MTAPE TO JOB DEVICE
;** HAVE AN IGNORE ERRORS SWITCH
;** THIS HORRIBLE BLETCHEROUS IOT CODE SHOULD BE REDESIGNED
;**
;********************************


IFN TM10A,TM10B==0
IFE TM10A,TM10B==1
IFN TM10A,INFORM IO BUSS MAG TAPE,1
IFN TM10B,INFORM DATA CHANNEL MAG TAPE,1
MSCBL==8	; COMMAND BUFFER LENGTH
MGQDLL==6	; INTERUPT LEVEL PDL
IF2 IFN MNUMB-140600, .ERR IMPLICIT DEPENDENCY ON MNUMB
MSEOFP==210100	;HIGH BIT OF MNUMB IN MEMBLT IS EOF FLAG
MSCHN==140500	;OTHER 5 BITS OF MNUMB IN MEMBLT IS DRIVE NUMBER

MTXP==410300,,	;XPORT NUMBER
MUNITF==170300	; UNIT FIELD IN MTC CONI
MNOPIN==10000
MWRITE==4000
MW3IN==14000
MSPRR==7000
MREAD==2000
MSPFR==6000
MSPFF==16000
MSPRF==17000
MREWND==1000
MRWNDD==11000
MWEOF==5000
MGNRTY==10.	;NUMBER OF READ RETRIES

SUBTTL MAG TAPE OPEN ROUTINE

;	C/	MODE,,DEV
;	D/	MODE (ROT 1) 4.9=1=>OUTPUT
;	I/	DEVICE NUMBER
;	R/	IOCHNM WORD POINTER

MAGTO:	SKIPL W,I	; GET DEVICE
	 CAIL W,NMTCS	; TO BIG?
	  JRST OPNL1	; NO SUCH DEVICE
	MOVSI T,%MAREW
	TDNE T,MSRAC(W)	; REWINDING
	 PUSHJ P,UFLS	; YES, THEN WAIT
	CONO PI,CLKOFF	; DON'T WANT STATUS CHANGED FROM UNDER ME
	SKIPGE MTUSE(W)	; CHECK FOR FIRST USER
	 JRST MAGTU1	; FIRST
	CAME U,MTUSR(W)	;SAME USER
	 JRST OPNL10	; DIFFERENT USER IS ERROR
	MOVE B,D
	EQV B,MSCRW(W)
	SKIPL B		; CHECK FOR SECOND OPEN IN SAME DIRECTION
	 JRST OPNL2	; WRONG DIRECTION
MAGTU:	MOVEM U,MTUSR(W)	; STORE USER
	SETZM MSCRW(W)	; INDICATE READ UNTIL FOUND TO BE OTHERWISE
	TLNE C,1	; READ OR WRITE
	 SETOM MSCRW(W)	;INDICATE WRITE
	AOS MTUSE(W)	;INDICATE 1 MORE USER
	PUSHJ P,SOSSET
	    MTUSE(W)	; SOS IF PCLSRED
	CONO PI,CLKON	; LET UM GET ME
	PUSHJ P,MTSTAT	; GET CONIS OF 340 AND 344 IN I AND J
	MOVE A,MSRAC(W)
	TLNE A,%MAERR	; PI ERROR MEANS DEVICE NOT THERE
	 JRST MTOL1
	TRNN J,200040
	 JRST OPNL7	; DEVICE NOT ONLINE
	SKIPN MSCRW(W)	;WRITING?
	 JRST MTOW1
	TRNE J,10	; AND WRITE LOCKED
	 JRST OPNL26	; DEVICE WRITELOCKED
	SKIPE MSRAC(W)	; WRITING
	 TRNN J,4000	;EOT?
	  JRST MTOW1	; NO
	MOVSI A,%MAETW+%MAERR	; IF WRITE AND EOT,MAKE .IOT GIVE IOC ERROR BUT LET OPEN WIN
	IORM A,MSRAC(W)
MTOW1:	TRNN J,400000	; XPORT HUNG
	 JRST MTOW2	; OK
	TRNN J,20000	; OK IF REWINDING
	 JRST OPNL7	;DEVICE NOT WORKING
MTOW2:	TLNN C,400	; GET CORE DUMP MODE
	 JRST MTOW3
	TLNN C,300
	 JRST MTOW3
	TLC C,300
	TLCE C,300	; IBM AND DENSITY 800 BPI OK
	 JRST OPNL12	; MODE NOT AVAILABLE
MTOW3:	;BY THIS POINT OPEN WILL WIN
	PUSHJ P,LSWDEL	; RELEASE MTUSE SWITCH
	MOVEI A,MTCCHN_3	;SET UP MAG TAPE CONO
IFN TM10A,	TRO A,1	; DATA PI CHANNEL
	LDB B,[300200,,C]	; GET DENSITY FROM OPEN
	SKIPN B
	 MOVEI B,3
	SUBI B,1	; CONVERT TO PROPER PARITY
	DPB B,[060200,,A]
	TLNN C,400	; CORE DUMP
	 TRO A,20000	; YES
	TLNN C,40	; PARITY CHECK
	 TRO A,40000	; SET ODD PARITY
	DPB W,[170300,,A]	; SET UNIT NUMBER
	MOVEM A,MTCONO(W)	; STORE IT
	LDB B,[330300,,C]	; GET WORDS PER BLOCK
	TRC B,7
	MOVEI A,10
	LSH A,(B)	;NUMBER OF WORDS PER RECORD
	MOVEM A,MTBLKS(W)	;BLOCKSIZE
	LDB A,[230200,,C]	; GET MODE (BUT NOT READ/WRITE BIT)
	HLR C,MTOPTB(A)	; GET INPUT DISPATCH
	TLNE D,400000	; OPEN FOR OUTPUT?
	 HRR C,MTOPTB(A);CHANGE TO OUTPUT IF SO
	MOVEM C,(R)	;STORE IN IOCHNM
	DPB W,[MTXP(R)]	; STORE XPORT NUMBER
	JRST POPJ1	; SKIP RETURN

MTOPTB:	MTUAIX,,MTUAOX
	MTBIX,,MTBOX
	MTUIIX,,MTUIOX
	MTBIX,,MTBOX

MAGTU1:	SETZM MSBUFP(W)	; INDICATE NO BUFFERS ON CHAIN
	SETZM MSNBOL(W)	; ANOTHER WAY OF SAYING ABOVE
	SETZM MSMPRC(W)	; BUFFER WORDS REMAINING
	SETZM MSMPRP(W)	; POINTER TO BUFFERS
	SETOM MTMDN(W)	;NO BUFFER AT MP
	SETOM MGCABN(W)	;NONE AT PI
	SETZM MSRAC(W)
	MOVEI A,2
	MOVEM A,MTCEFW(W)	; NUMBER OF EOF'S WRITTEN
	MOVSI A,%MANWT
	IORM A,MSRAC(W)	; INDICATE NOTHING WRITTEN ON TAPE
	JRST MAGTU

MTOL1:	SETZM MSRAC(W)
	JRST OPNL1

SUBTTL MAG TAPE INPUT .IOT ROUTINES

	SKIPA B,[SIOKT]
MTUAI:	 MOVEI B,CHRKTI	;UNIT ASCII INPUT
	MOVE E,[440700,,5]
	JRST MTREAD

	SKIPA B,[SIOKT]
MTUII:	 MOVEI B,CHRKTI	;UNIT IMAGE
	MOVE E,[444400,,1]
	JRST MTREAD

MTBI:	MOVE E,[444400,,1]	;BLOCK INPUT
	MOVEI B,BLKT
MTREAD:	LDB W,[MTXP(R)]	; W <= XPT #
	PUSHJ P,MTIECK
	MOVEM P,MTPSAV(W)	; SAVE P FOR EOF RETURN
	JSP B,(B)	;BLKT,CHRKT,SIOKT
	    MSMPRP(W)	;LOC OF NEXT WORD
	    MSMPRC(W)	;COUNT REMAINING
	    SETZ MTRBG	; GET NEW BUFFER (SETZ FOR CHRKT RETURN ON EOF)
	    MTRBD	; DISCARD BUFFER
	    JRST 4,.
	    PUSHJ P,MTRBFW	; FLUSH INSTRUCTION WAIT FOR BUFFERS TO COME FROM PI

;MAG TAPE READ BUFFER GET ROUTINE
; BUFFER ASSUMED TO HAVE COME IN FROM PI LEVEL.  (I.E. MTRBFW WAS CALLED)

MTRBG:	SKIPG MSNBOL(W)		;ANY BUFFER AVAILABLE?
	 JRST MTRBG3		;NO, MUST BE ERROR OR EOF
	CONO PI,UTCOFF
	HLRZ A,MSBUFP(W)	; GET IN POINTER
	HRRZ TT,MSBUFP(W)	; GET OUT POINTER
	MOVEM TT,MTMDN(W)	; STORE BUFFER ACTIVE AT MP
	CAMN A,TT		;IN = OUT?
	 JRST MTRBG1		; YES
	LDB T,[MLO,,MEMBLT(TT)]	; BACK POINTER TO NEXT BLOCK
	HRRM T,MSBUFP(W)	;STORE NEW OUT POINTER
	JRST MTRBG2

MTRBG1:	SETZM MSBUFP(W)	;EMPTY BUFFER LIST
MTRBG2:	SOS MSNBOL(W)		; ONE LESS BUFFER ON LIST
	CONO PI,UTCON
	LDB J,[MWC,,MEMBLT(TT)]	;WORD COUNT OF BLOCK
	MOVEM J,MTBLKS(W)	;SAVE FOR MTAPE 13
	LSH TT,10.		;MAKE BLOCK NUMBER AN ADDRESS
	MOVEM TT,MSMPRP(W)
	JRST SIOBGX

MTRBG3:	SKIPGE MSRAC(W) .SEE %MAEOF
	 JRST [	MOVSI T,%MAEFA	;THE EOF IS NOW NO LONGER READ-AHEAD
		ANDCAM T,MSRAC(W)	;TELL THE USER ABOUT IT
		JRST POPJ2 ]
	PUSHJ P,MTIECK
	JRST 4,.		;BULLSHIT, WHY DID MTRBFW SKIP?

;MAG TAPE READ BUFFER DISCARD ROUTINE
MTRBD:	SKIPGE A,MTMDN(W)	; ANY BUFFERS
	 JRST MOVTWJ	;SET UP T FOR BUFFER WAIT,RETURN
	CONO PI,UTCOFF	; SHUT UP WORLD
	SETOM MTMDN(W)	; NO BUFFER ACTIVE AT M.P.
	SETZM MSMPRC(W)
	LDB TT,[MSEOFP,,MEMBLT(A)]	;GET EOF FLAG FROM PI
	PUSHJ P,MGMEMR	;RETURN MEM, TURN UTCON
	JUMPN TT,MTRBD2	;EOF?
MOVTWJ:	MOVE T,W	; T NEEDS CHANNEL NUMBER FOR BUFFER WAIT UFLUSH
	POPJ P,		;ALSO MTRBG, MTRBFW RELY ON THIS SETTING T

MTRBD2:	MOVSI A,%MAEOF	; SET EOF
	IORM A,MSRAC(W)
	JRST MOVTWJ

;MAG TAPE READ WAIT FOR DATA ROUTINE
MTRBFW:	SKIPG MSNBOL(T)	; ANY FREE BUFFERS ON LIST?
	 SKIPGE MSRAC(T) .SEE %MAEOF
	  JRST POPJ1	;INPUT AVAILABLE, OR AT EOF, UNHANG
	MOVE TT,MSRAC(T)
	TLNE TT,%MAERR	; CHECK FOR ERRORS
	 JRST POPJ1	;WAKE UP SO YOU CAN GET YOUR IOC ERROR
	TLNE TT,%MARAC	; IF NOT ALREADY DONE SO, SEND OUT A CALL FOR TAPE READ
	 POPJ P,
	PUSH P,W	;THIS BEING DONE UNDER A UFLS. ONLY T GOOD
	PUSH P,B
	MOVE W,T
	MOVEI B,MGREAD	;WHERE TO GO AT PI LEVEL
	MOVEI T,MSCBL	;MAKE SURE THAT THERE IS ROOM IN THE RING BUFFER
	CAMG T,MSCMDC(W)
	 JRST MTRBW2	; NO ROOM, GO AWAY
	MOVSI TT,%MARAC
	IORM TT,MSRAC(W)	;READ IS ACTIVE NOW, OR WILL BE SHORTLY
	PUSHJ P,MTCMD1
MTRBW2:	MOVE T,W
	POP P,B
	POP P,W
	POPJ P,

SUBTTL MAG TAPE OUTPUT .IOT ROUTINES

	SKIPA B,[SIOKT]
MTUAO:	 MOVEI B,CHRKT	;UNIT ASCII OUTPUT
	MOVE E,[440700,,5]
	JRST MTWRIT

	SKIPA B,[SIOKT]
MTUIO:	 MOVEI B,CHRKT	;UNIT IMAGE OUTPUT
	MOVE E,[444400,,1]
	JRST MTWRIT

MTBO:	MOVE E,[444400,,1]	; BLOCK OUT
	MOVEI B,BLKT
MTWRIT:	LDB W,[MTXP(R)]	; GET XPORT NUMBER
	PUSHJ P,MTIECK
	HRLZI A,%MAETW	; END OF TAPE CHECK
	TDNE A,MSRAC(W)
	 JRST IOCER9
	JSP B,(B)
	    SETZ MSMPRP(W)	;LOC OF WORD
	    MSMPRC(W)	; COUNT
	    SETZ MTWBFG	; GET NEW BUFFER
	    MTWBFD	; WRITE OUT BUFFERS
	    JRST 4,.
	    TRNA	;NO WAIT FOR BUFFER

;MAG TAPE WRITE BUFFER GET ROUTINE

MTWBFG:	PUSHJ P,MTIECK
	PUSHJ P,TCALL		; TURN OFF UTC
	    JRST IOMQ
	 POPJ P,		;GO BACK NO SKIP IF NO CORE
	MOVEM A,MTMDN(W)	; STORE ACTIVE BUFFER NUMBER
	MOVEI T,MUMGB
	DPB T,[MUR,,MEMBLT(A)]	; TELL WORLD THAT IT IS A MAG TAPE BUFFER
	DPB W,[MSCHN,,MEMBLT(A)]	; CHANNEL NUMBER
	SETZM TT
	DPB A,[121000,,TT]	;CONVERT BLOCK NUMBER TO ADDRESS IN TT
	MOVE J,MTBLKS(W)	;GET WRITE BLOCK SIZE
	JRST SIOBGX

;MAG TAPE WRITE BUFFER DISCARD ROUTINE

MTWBFD:	PUSHJ P,MTIECK
	SKIPGE A,MTMDN(W)
	 POPJ P,
	MOVEI T,MSCBL
	CAMG T,MSCMDC(W)
	 PUSHJ P,UFLS	; MAKE SURE ROOM IN COMMAND BUFFER EXISTS IN CASE OF PCLSRING
	MOVE T,MTBLKS(W)	; DISCARD BUFFER. FIRST SEE HOW BIG IT IS
	SUB T,MSMPRC(W)
	CONO PI,UTCOFF	;CAN'T TOLERATE ANY HANKY PANKY
	SETOM MTMDN(W)	;CLEAR IT
	SETZM MSMPRC(W)	; CLEAR COUNT
	JUMPE T,MEMR	; DON'T DO ANYTHING BUT RETURN BLOCK IF NO WORDS
	DPB T,[MWC,,MEMBLT(A)]	; STORE WORD COUNT
	SKIPG MSNBOL(W)	; LIST STARTED YET?
	 JRST MTWBD1	;NO
	HLRZ TT,MSBUFP(W)	; GET OLD IN POINTER
	DPB A,[MLO,,MEMBLT(TT)]	;CHAIN BACK
	SKIPA
MTWBD1:	 HRRM A,MSBUFP(W)	; START NEW LIST
	HRLM A,MSBUFP(W)	; IN = OUT = (A)
MTWBD2:	SETZM TT
	DPB TT,[MLO,,MEMBLT(A)]	; INDICATE END OF LIST
	AOS MSNBOL(W)	; ONE MORE BUFFER ON LIST
	CONO PI,UTCON
	PUSH P,B
	MOVEI B,MGWRIT
	PUSHJ P,MTCMD	
	MOVSI B,%MANWT
	ANDCAM B,MSRAC(W)
	SETZM MTCEFW(W)	; INDICATE SOMETHING WRITTEN
	JRST POPBJ	; RETURN

SUBTTL MTCMD - GIVE COMMAND TO PI LEVEL

;PUSHJ P,MTCMD
	;RH(W) HAS XPORT NUMBER
	;RH(B) HAS ADDR OF INTERUPT ROUTINE

MTCMD:	MOVEI T,MSCBL	; COMAND BUFFER LENGTH
	CAMG T,MSCMDC(W)	;COMAND COUNT
	 PUSHJ P,UFLS	; WAIT FOR ROOM
MTCMD1:	MOVE T,MTCMBP(W)	; GET POINTER TO RING BUFFER
	AOBJN T,.+2
	 SUB T,[MSCBL,,MSCBL]	; REACHED END OF BUFFER, RING IT
	MOVEM B,(T)	; STORE COMMAND
	MOVEM T,MTCMBP(W)	; STORE NEW POINTER
	CONO PI,UTCOFF
	AOS MSCMDC(W)	; INDICATE ONE MORE COMMAND
	JRST MSTRTR	; START UP PI ROUTINE

SUBTTL MTIECK - CHECK FOR IOC ERROR

MTIECK:	PUSH P,A	; CHECK FOR IOTERR
	MOVE A,MSRAC(W)
	TLNN A,%MAERR	; ERROR AT PI?
	 JRST POPAJ
	SKIPLE MSCMDC(W)
	 PUSHJ P,UFLS	; LET PI CLEAR BEFORE MUNGING BUFFERS
	SKIPL A,MTMDN(W)
	 PUSHJ P,MEMR
	SETOM MTMDN(W)
	SETZM MSMPRP(W)
	SETZM MSMPRP(W)
	PUSHJ P,MTCBFF	; FREE CHAIN
	POP P,A
	MOVE T,MGCMTS(W)	; GET CONI MTS,
	TRNE T,440000	; XPT HUNG,ILLOP
	 JRST IOCER1
	TRNE T,23600	; PAR ERROR,R/C, RLI,DL,BT
	 JRST IOCER3	; IRRECORVERABLE DATA ERROR
	TRNE T,4000	; EOT
	 JRST IOCER9	; EOT, DEV FULL
	MOVE A,MGEOFR(W)	; LOGICAL EOT
	CAIL A,2
	 JRST IOCER9
	JRST IOCER3	; UNKNOWN, GIVE IRR DATA

SUBTTL MAG TAPE .STATUS ROUTINE

STAMTC:	LDB W,[MTXP(R)]	; LOAD W
	DPB A,[60300,,D]	; OPEN MODE
	PUSHJ P,MTSTAT
	LDB A,[.BP %MAETW_22,MSRAC(W)]	; EOT ON WRITE
	LDB B,[.BP %MAETR_22,MSRAC(W)]	; EOT ON READ
	IOR A,B
	DPB B,[140100,,D]	;EOT
	LDB A,[20100,,J]
	TRC A,1
	DPB A,[150100,,D]	; 7 OR 9
	LDB A,[160100,,MTCONO(W)]
	TRC A,1
	DPB A,[200100,,D]	;PARITY
	LDB A,[60200,,MTCONO(W)]	; DENSITY
	ADDI A,1
	CAIN A,3
	 SETZM A	; 800 IS 00
	DPB A,[160200,,D]
	LDB A,[.BP %MARCE_22,MSRAC(W)]	; READ COMPARE ERROR
	DPB A,[130100,,D]
	MOVE A,MTCONO(W)
	TRNN J,4	; 7 TRACK
	 TRNE A,20000	; OR CORE DUMP
	  POPJ P,	; THEN DONE
	TRO D,140000	; IBM, 9 TRACK AND 800 BPI
	POPJ P,


;RCHST ROUTINE FOR MAG TAPE

RCHMGT:	HLRZ E,(R)	;OPEN-MODE IS KEPT IN LH OF IOCHNM WORD - HOW CONVENIENT!
	LDB J,[MTXP(R)]	;GET THE MAG TAPE DRIVE NUMBER
	MOVSI J,'MT0(J)	;RETURN THAT DRIVE'S DEVICE NAME.
	TRZ E,(.BM MTXP) ;CLEAR THE PLACE IN THE OPEN-MODE THAT HAS THE DRIVE #.
	JRST POPJ1	;SKIP SO THAT J OVERRIDES BUILT-IN DEVICE NAME.

EBLK

SUBTTL MAG TAPE STORAGE AREA

MGVTC:	0	; 1 SCRATCH WORD FOR VIRGIN TAPE CHECK
MGRWCD:	BLOCK NMTCS	; REWIND COMMAND
MGEOTT:	BLOCK NMTCS	; TIMEOUT FOR VIRGIN TAPE
MGJDTI:	0	; WAIT FOR JOB DONE TIME OUT
MGEOFR:	BLOCK NMTCS	; NUMBER OF EOFS SINCE LAST READ
MGNWRD:	0	; NUMBER OF WORDS READ IN A PI LEVEL READ
MTPSAV:	BLOCK NMTCS	; STORAGE TO RESTORE P ON EOF
MSRAC:	BLOCK NMTCS	; MAG TAPE GENERAL GARBAGE
 %MA==1,,525252
 %MAEOF==400000		; 4.9 EOF ON READ
 %MAETR==200000		; 4.8 EOT ON INTERNAL READ
 %MAETW==100000		; 4.7 EOT ON WRITE
 %MAERR==040000		; 4.6 PI ERROR
 %MARCE==020000		; 4.5 READ COMPARE ERROR
 %MACTH==014000		; 4.4 CORE ALLOCATOR SAYS STOP
			; 4.3 "  (WHY 2 BITS?)
 %MASTP==002000		; 4.2 STOP READ AHEAD
 %MANWT==001000		; 4.1 NOTHING WRITTEN ON TAPE YET
 %MAEFA==000400		; 3.9 EOF SEEN ON READ-AHEAD, USER HASN'T SEEN YET
 %MAESO==000200		; 3.8 EOF READ SINCE OPEN
 %MAMSO==000100		; 3.7 TAPE MOVED SINCE FIRST OPEN
 %MAREW==000040		; 3.6 REWINDING FLAG
 %MARAC==000020		; 3.5 READ ACTIVE FLAG
MGTBZY:	-1		; FLAG TO GET INTURPT STARTED
MTCONO:	REPEAT NMTCS,\.RPCNT_17+20	; MAIN CONO STORAGE
MGUNIT:	-1		; UNIT EXPECTING INTERUPT
MGCMTS:	BLOCK NMTCS	; PI CONI MTS STORAGE
MGCMTC:	BLOCK NMTCS	; PI MTC STORAGE
MGWCW:	0		; WAIT FOR CONTROL WORD WRITTEN FLAG
LMIOWD:	0		; LAST MIOWD
MGERRC:	BLOCK NMTCS	; ERROR COUNT
MTMFNC:	BLOCK NMTCS	; .MTAPE FUNCTION STORAGE
MTMCNT:	BLOCK NMTCS	; .MTAPE COUNT
MTMTAP:	BLOCK NMTCS	; MTAPE CALL WORD
MTCEFW:	BLOCK NMTCS	; NUMBER OF EOF'S WRITTEN AT CLOSE
MSCMDC:	REPEAT NMTCS,0	; NUMBER OF COMMANDS
MSBUFP:	REPEAT NMTCS,0	; MAG TAPE BUFFER POINTER  IN,,OUT
MSCRW:	BLOCK NMTCS	; -1=>OUTPUT 0=>INPUT
MSMPRC:	BLOCK NMTCS	; WORDS LEFT IN BUFFER
MSMPRP:	BLOCK NMTCS	;NEXT WORD IN BUFFER
MTMDN:	REPEAT NMTCS,-1	; BLOCK ACTIVE AT MP
MTUSE:	REPEAT NMTCS,-1	; NUMBER OF CHANNELS OPEN ON THIS MTAPE
MTUSR:	REPEAT NMTCS,-1	; USER INDEX OF XPORT
MSNBOL:	BLOCK NMTCS	; NUMBER OF BUFFERS ON LIST
MGCABN:	REPEAT NMTCS,-1	; BUFFER ACTIVE AT PI LEVEL
MTBLKS:	BLOCK NMTCS	; WRITE, BUFFER SIZE
			; READ, SIZE OF LAST RECORD READ
MGQDLP:	REPEAT NMTCS,-MGQDLL,,CONC MGQD,\.RPCNT,-1	;QDL POINTER
REPEAT NMTCS,[
	CONC MSCB,\.RPCNT,:	BLOCK MSCBL	; COMMAND BUFFER
				MGRCV	; TO RING BUFFER

				MGNCMD	; GET NEW COMMAND
	CONC MGQD,\.RPCNT,:	BLOCK MGQDLL
	IFE .RPCNT,MSLCTB==.-MSCB0	; LENGTH OF EACH TABLE
]
MTCMBP:	REPEAT NMTCS,-MSCBL-1,,CONC MSCB,\.RPCNT,-1	; INPUT TO COMMAND TABLE
MGCMBP:	REPEAT NMTCS,4400,,CONC MSCB,\.RPCNT,-1	; OUTPUT FROM COMAND TABLE
IFE KL10P,MIOWD: BLOCK 2	; CHANNEL PROGRAM
IFN TM10A,[
MGDBRK:	0
	CONO MTS,1
	JRST 12,@MGDBRK
];TM10A
MGEMTC:	0	;CONI MTC, AT LAST ERROR
MGEMTS:	0	;CONI MTS, AT LAST ERROR
BBLK

SUBTTL MAG TAPE PI LEVEL

;ROUTINES TO GET INTERUPT ROUTINES STARTED
MGXGO:	MOVE Q,MGQDLP(W)	;GET QDLPOINTER
	PUSHJ P,QPOPJ	;CALL ROUTINE . SHOULD FINISH WITH POPJ P,OR PUSHJ Q,CPOPJ
			;PUSHJ Q,CPOPJ IF ROUTINE WANTS TO RETURN
			;POPJ P, IF AT END OF COMAND. AND NEW IS TO BE GOTTEN
	MOVEM Q,MGQDLP(W)	; STORE NEW QDL
	POPJ P,

MGRCV:	MOVNI A,MSCBL+1	;AT END OF COMAND LIST,RING IT
	ADDM A,MGCMBP(W)	;RING THE BUFFER
MGNCM1:	ILDB B,MGCMBP(W)	; GET NEW COMMAND
	JRST (B)

MGNCMD:	AOBJN Q,MGNCM1	; AT BOTTOM OF QDL, SIMULATE PUSHJ AND GET NEW COMMAND
	JRST 4,.	;QDL POINTER CLOBBERED

QPOPJ1:	AOS (Q)
QPOPJ:	POPJ Q,

MSTRTR:	CONO PI,UTCOFF	; GET MAGTAPE INTURPT STARTED
	SETZM MGTBZY
	CONO PI,MTCRQ
	CONO PI,UTCON
	POPJ P,

;HERE FOR MAG TAPE FLAG CHANNEL INTERUPT
MGHBRK:	SKIPGE W,MGUNIT	; LOAD UNIT
	 JRST MGUBRK	;NO ONE WANTS IT
	LDB B,[MUNITF,,A]
	CAME W,B	; UNITS AGREE
	 JRST 4,.	; WE MUST NOT MIX UNITS
	MOVE J,C
	PUSH P,[DSKEX]
IFN TM10B,[
	TLNE C,160
	 JRST MGERR
];TM10B
	TRNE C,40000
	 JRST MGERR
	JRST MGXGO

MGSBRK:	SETOM MGTBZY	;HERE FOR ANY RANDOM MP PI STARTUP
	MOVEI B,NMTCS-1
	SKIPG MSCMDC(B)	;ANY COMMANDS IN BUFFER
MGSBK1:	 SOJGE B,.-1
	SKIPGE B	;LAST UNIT?
	 JRST DSKEX	; THEN GOTO DSKEX
	MOVE W,B
	PUSH P,B
	MOVSI B,%MACTH
	TDNN B,MSRAC(W)	; CORE ALLOCATOR SAYING GO AWAY
	 PUSHJ P,MGXGO	; START UP THAT ROUTINE
	POP P,B
	JRST MGSBK1	; ANY MORE?

MGUBRK:	LDB W,[MUNITF,,A]	; WHO CAUSED INTERUPT?
	MOVE B,MTCONO(W)
	CONO MTC,(B)
	CONO MTS,31	; CLEAR INTERUPT
	JRST DSKEX

;	ROUTINE TO WAIT FOR JOB DONE TO SET
MGWTJD:	CONI MTS,J
	TRNE J,440000	;SKIP IF STARTED SUCCESSFULLY
	 JRST MGERR	;JOB-DONE ISN'T EVER GOING TO SET
MGWJD1:	CONI MTS,J
	SKIPN MGJDTI	; TIME OUT?
	 JRST MGWJD2
	MOVE T,TIME
	CAML T,MGJDTI
	 JRST MGERR
MGWJD2:	TRNN J,100	; JOB DONE?
	 JRST MGOVER	; NOT SET
	CONI MTS,J
	CONI MTC,I	; GET CONI MTC
	MOVEM J,MGCMTS(W)
	MOVEM I,MGCMTC(W)
	SKIPE MGWCW	; SHOULD I WAIT FOR CONTROL WORD WRITTEN
	 PUSHJ Q,MGWCWC	; CHECK TO SEE IF IT IS WRITTEN
	SETZM MGWCW	;CLEAR FLAG
	CONO MTS,30	; CLEAR CHANNEL CONDITIONS
	MOVE B,MTCONO(W)
	CONO MTC,(B)	; RELESE MTC, CLEAR JOB DONE
IFN TM10B,[
	TLNE J,160
	 POPJ Q,	;CHANNEL ERROR
]
	TRNE J,463600
	 POPJ Q,	; RANDOM OTHER NON PERFECTIONS, NOT NECESSARILY ERRORS
	JRST QPOPJ1	; SUCCESS

;	GET XPORT
MGGXPT:	CONSO MTS,2	; LOAD NEXT UNIT SET?
	 JRST MGOVER	; NO, WAIT FOR IT
	MOVEM W,MGUNIT
	MOVE T,TIME
	ADDI T,10.*30.	; TIME OUT IN 10. SECONDS
	MOVEM T,MGJDTI
	MOVE B,MTCONO(W)
	CONO MTC,MNOPIN(B)	; SELECT DRIVE
	PUSHJ Q,MGWJD1
	 JFCL		; WAIT FOR JOB DONE, BUT ALLOW ANY ERRORS
	SETZM MGJDTI
	POPJ Q,

MGOVER:	CONSZ MTS,440020	; ANY PROBLEMS?
	 JRST MGERR	;TAPE HUNG, ILL FUNCTION, CHANNEL ERROR
	SOS (Q)
	POPJ P,

;ERROR
MGERR:	CONI MTS,MGEMTS
	CONI MTC,MGEMTC
	MOVSI T,%MARAC	;READ NOT ACTIVE, FOR SURE
	ANDCAM T,MSRAC(W)
	SETZM MSCMDC(W)	; NO COMMANDS
	SETOM MGUNIT	; CLEAR UNIT WAIT FLAG
	SETZM MGJDTI
IFN TM10B,[
	TLNE J,160	; CHANNEL ERROR?
	 BUG PAUSE,[MTAPE: CHANNEL ERROR, STATUS=],OCT,J,[MICWA+1=],OCT,MICWA+1,[MIOWD=],OCT,MIOWD
];TM10B
	SKIPL A,MGCABN(W)	; ANY PI BUFFERS?
	 PUSHJ P,IMEMR
	SETOM MGCABN(W)
	HRLZI B,%MAERR	; PI ERROR
	IORM B,MSRAC(W)	; STORE IN STATUS WORD
	MOVE Q,[-MGQDLL,,MGQD0-1]
	MOVE T,MSLCTB
	IMUL T,W
	ADD Q,T		; RESTORE Q
	PUSH P,Q
	MOVE Q,[-MSCBL-1,,MSCB0-1]
	ADD Q,T
	MOVEM Q,MTCMBP(W)	; INITIALIZE MP AND PI COMMND POINTERS
	MOVE Q,[4400,,MSCB0-1]
	ADD Q,T
	MOVEM Q,MGCMBP(W)
	MOVSI B,%MAREW
	ANDCAM B,MSRAC(W)	; CLEAR REWINDING
	SKIPN MSCRW(W)	; DONE IF READING
	 JRST POPQJ
	SKIPN MSNBOL(W)	; ANY BUFFERS ON LIST?
	 JRST POPQJ
MGERR1:	HRRZ A,MSBUFP(W)
	PUSHJ P,MTICL1
	PUSHJ P,IMEMR
	SOSLE MSNBOL(W)	; ANY MORE
	 JRST MGERR1
	SETZM MSBUFP(W)	;EMPTY LIST
	JRST POPQJ

MGWCWC:
IFN TM10B,[
	SKIPE MICWA+1	; CONTROL WORD WRITTEN?
	 POPJ Q,
	CONO MTS,4	; TELL IT TO WRITE IT
MGWCW1:	SKIPE MICWA+1
	 JRST MGWCW2	; DONE
	PUSHJ Q,CPOPJ	; WAIT
	JRST MGWCW1

MGWCW2:	MOVE I,MGCMTC(W)
	MOVE J,MGCMTS(W)	;RESTORE STATUS
	TLO J,10	;SET CONTROL WORD WRITTEN
]		;END OF IFN TM10B
	POPJ Q,

IFN TM10A,[
MGDCSI:	SKIPA A,[BLKI MTC,MIOWD]
MGDCSO:	 MOVE A,[BLKO MTC,MIOWD]
	MOVEM A,MAGLOC
	MOVE A,[JSR MGDBRK]
	MOVEM A,MAGLOC+1
	POPJ Q,
]		;END OF IFN TM10A

SUBTTL MAG TAPE PI LEVEL WRITE

MGWRIT:	PUSHJ Q,MGGXPT	; GET XPORT
	TRNE J,600010	; WRITE LOCKED,HUNG OR REWINDING
	 JRST MGERR
	MOVEM W,MGUNIT	; SET UNIT
	MOVSI A,%MACTH	; CORE ALLOC WANT QUIT TEMPORARLY
	TDNE A,MSRAC(W)
	 JRST MGWRT4
	HRRZ A,MSBUFP(W)	; GET BUFFER POINTER
	HLRZ B,MSBUFP(W)	; IN POINTER
	SOS MSNBOL(W)	; ONE LESS BUFFER
	MOVEM A,MGCABN(W)	; BUFFER ACTIVE AT PI
	SKIPN MSCRW(W)	; WRITING
	 JRST 4,.
	CAME A,B	; IN = OUT
	 JRST MGWRT1
	SETZM MSBUFP(W)	; EMPTY BUFFER LIST
	JRST MGWRT2

MGWRT1:	LDB B,[MLO,,MEMBLT(A)]	; BACK POINTER
	HRRM B,MSBUFP(W)	; NEW OUT POINTER
MGWRT2:	LDB B,[MWC,,MEMBLT(A)]	; WORD COUNT
	MOVNS B		; NEGATE
	HRLZS B		; FORM COUNT
IFN KL10P, LSH B,4	; SHIFT IF KL10 DATA CHANNEL
IFN KL10P, MOVE R,A	; SAVE CORE PAGE NUMBER FOR CACHE SWEEP
	LSH A,10.	; FORM WORD POINTER
	SUBI A,1
	HRRM A,B	; CHANNEL POINTER IN B
IFN TM10B,	DATAO MTS,[MICWA]	; SET TO GO TO MAG TAPE
IFN TM10A,	PUSHJ Q,MGDCSO
	MOVEM B,MIOWD
	MOVEM B,LMIOWD	; LAST MIOWD
	SETZM MIOWD+1	; TELL CHANNEL TO STOP
IFN KL10P,[
	PUSHJ P,CSHSWP	; UNLOAD BUFFER FROM CACHE INTO CORE
	  CAI
]
	MOVE B,MTCONO(W)
	CONO MTC,MWRITE(B)	; DO IT
	PUSHJ Q,MGWTJD	; WAIT FOR JOB DONE
	 JRST MGWBT	; WRITE BLANK TAPE AND TRY AGAIN
MGWRT3:	MOVE A,MGCABN(W)	; GET BUFFER NUMBER
	HRLZI B,%MAETW+%MAERR	; END OF TAPE CHECK
	TRNE J,4000	; END POINT
	 IORM B,MSRAC(W)	; TELL MP
	LDB T,[MUR,,MEMBLT(A)]
	CAIE T,MUMGB	; DO I OWN BLOCK
	 JRST 4,.
	SETOM MGCABN(W)	; NO BUFFER ACTIVE AT PI
	PUSHJ P,IMEMR	; GIVE BACK BUFFER
	MOVSI A,%MAMSO
	IORM A,MSRAC(W)	; TAPE MOVEMENT
	JRST MGCMDR

MGWBT:
IFN TM10B,	SETZM MIOWD	; WRITE BLANK TAPE OVER POSSIBLE BAD SPOT
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD	; ONE RECORD
]
	TRNE J,644010	; BAD TYPES OF ERRORS
	 JRST MGERR
	MOVE B,MTCONO(W)
	CONO MTC,MSPRR(B)	; REVERSE 1 RECORD
	PUSHJ Q,MGWTJD	; WAIT FOR JOB DONE
	 JRST MGERR	; ERROR
	MOVE B,LMIOWD
	MOVEM B,MIOWD	; RESTORE MIOWD
	MOVE B,MTCONO(W)
	CONO MTC,14000(B)	; WRITE WITH EXTENDED EOR
	PUSHJ Q,MGWTJD	; WAIT
	 JRST MGWBT	; INFINITE RETRIES ;	JRST MGERR	; ERRORS
	JRST MGWRT3

MGWRT4:	PUSHJ Q,CPOPJ	; WAIT A WHILE
	JRST MGWRIT

SUBTTL MAG TAPE PI LEVEL READ

MGREAD:	PUSHJ Q,MGGXPT	; GET XPORT
MGRD0:	TRNE J,600000	; UNIT HUNG OR REWINDING OR EOT
	 JRST MGERR
	MOVE B,MGEOFR(W)	; EOF'S READ
	CAIL B,2
	 JRST MGERR
	MOVEM W,MGUNIT	; STORE UNIT NUMBER
	SKIPE MSCRW(W)	; MAKE SURE READING
	 JRST 4,.
	MOVSI B,%MACTH	; CORE ALLOCATOR WANT OUT
	TDNN B,MSRAC(W)
	 PUSHJ P,IOMQ
	  JRST MGROVR	; WAIT FOR IT
	MOVEM A,MGCABN(W)	; STORE ACTIVE BUFFER AT PI LEVEL
	MOVEI B,MUMGB
	DPB B,[MUR,,MEMBLT(A)]	; CLAIM BLOCK
	HRREI B,-MGNRTY	; NUMBER OF RETRIES
	MOVEM B,MGERRC(W)	; STORE ERROR COUNT
IFN KL10P, MOVE R,A
	LSH A,10.	; FORM ADDRESS
	SUBI A,1
IFE KL10P,	HRLI B,-2000
IFN KL10P,	HRLI B,-2000_4
	HRR B,A
	MOVEM B,LMIOWD	; STORE LAST IOWD FOR RETRY
IFN TM10B,	DATAO MTS,[MICWA]	; SET CHANNEL STARTING ADDRESS
IFN TM10A,	PUSHJ Q,MGDCSI
IFN TM10B,	SETZM MICWA+1
	SETZM MIOWD+1
MGRD1:	MOVEM B,MIOWD	; CHANNEL COMMAND
	MOVEI B,2000
	MOVEM B,MGNWRD	; ASSUME AT FIRST THAT THE RECORD TO BE READ HAS 2000 WORDS
IFN KL10P,[
	PUSHJ P,CSHSWP	; ENSURE NO RESIDUE OF THIS PAGE IN CACHE
	    CAIA
]
	MOVE B,MTCONO(W)
	CONO MTC,MREAD(B)	; DO IT
IFN TM10B,	SETOM MGWCW	; TELL IT TO WAIT FOR CONTROL WORD WRITTEN
	PUSHJ Q,MGWTJD	; WAIT FOR JOB DONE
	 JRST MGRERR
MGRD2:	SKIPG A,MGCABN(W)
	 BUG			;BUFFER SHOULDN'T BE -1, WOULD SCREW UP MEMBLT
	SETOM MGCABN(W)		; NO BUFFER ACTIVE AT PI
	HLRZ T,MSBUFP(W)	;LAST BUFFER IN
	SETZM B
	DPB B,[MLO,,MEMBLT(A)]	;  BACK POINTER IS 0
	SKIPG MSNBOL(W)
	 HRRM A,MSBUFP(W)	; ONE BUFFER MEANS IN = OUT
	HRLM A,MSBUFP(W)	; NEW IN POINTER
	SKIPLE MSNBOL(W)
	 DPB A,[MLO,,MEMBLT(T)]	; CHAIN BACK BUFFERS
	AOS C,MSNBOL(W)		; ONE MORE BUFFER ON LIST (COUNT TO C)
	MOVE B,MGNWRD
	DPB B,[MWC,,MEMBLT(A)]	; NUMBER OF WORDS IN BUFFER
	TRNE J,10000		;EOF?
	 JRST [	MOVSI B,%MAESO+%MAEFA	;YES
		IORM B,MSRAC(W)
		SETO B,
		DPB B,[MSEOFP,,MEMBLT(A)]
		AOS A,MGEOFR(W)
		CAIL A,2
		 JRST MGRD4	; LOGICAL EOT, SPACE BACK OVER IT
		JRST .+2 ]
	  SETZM MGEOFR(W)	; NO EOF
	MOVSI A,%MAMSO
	IORB A,MSRAC(W)	; TAPE MOVEMENT
	TRNE J,4000	; EOT?
	 JRST MGRD3
	TRNN J,10000		;IF NO EOF, NOT 6 BUFFERS YET,
	 CAIL C,6
	  JRST MGRD5
	TLNN A,%MASTP
	 JRST MGRD0		; AND NO REQUEST TO STOP, KEEP READING
MGRD5:	MOVSI A,%MASTP+%MARAC	;GIVE UP FOR NOW, CLEAR READ ACTIVE
	ANDCAM A,MSRAC(W)
	JRST MGCMDR		;MP LEVEL WILL SEND NEW READ COMMAND WHEN READY

MGRD3:	DPB B,[MSEOFP,,MEMBLT(A)]	;PHYSICAL EOT
	DPB B,[420100,,MSRAC(W)] .SEE %MAETR	; INDICATE EOT ON READ
	JRST MGRD5	; RETURN

MGRD4:	MOVSI A,%MAESO+%MARAC+%MASTP	;SECOND EOF, LOGICAL EOT
	ANDCAM A,MSRAC(W)
	JRST MGSPRF

MGRERR:
IFN TM10B,[
	TLNE J,160
	 JRST MGERR	; CHANNEL ERROR
]
	TRNE J,642000
	 JRST MGERR
	TRNE J,20600
	 JRST MGMRT	; DATA TYPE OF ERROR OR OVERRUN, MAYBE TRY AGAIN
;RECORD LENGTH ERROR, ADJUST MGNWRD
IFN TM10B,	HRRZ A,MICWA+1
IFN TM10A,	HRRZ A,MIOWD
	HRRZ B,LMIOWD
	SUB A,B
IFN TM10B,	SOS A	; CHANNEL FUNNYNESS
	CAIN A,1	; POS EOF IS ALL
	 JRST MGRER2
MGRER1:	MOVEM A,MGNWRD
	JRST MGRD2

MGRER2:	TRNE J,14000	; 1 WORD, EOF? EOT?
	 SETZM A	; YES, THIS RECORD HAS ZERO LENGTH, IT JUST CARRIES MSEOFP
	JRST MGRER1

MGMRT:	AOSL MGERRC(W)
	 JRST MGERR	; TOO MANY ERRORS
IFN TM10B,	SETZM MIOWD
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD	; ONE RECORD
	PUSHJ Q,MGDCSO
]
	MOVE B,MTCONO(W)
	CONO MTC,MSPRR(B)	; REVERSE RECORD
	PUSHJ Q,MGWTJD
	 JRST MGERR	; NO ERRORS ALLOWED
IFN TM10A,	PUSHJ Q,MGDCSI	; PUT BACK PI 1 BLKI
	MOVE B,LMIOWD
	JRST MGRD1	; TRY AGAIN

MGROVR:	PUSHJ Q,CPOPJ
	JRST MGREAD

SUBTTL MAG TAPE PI LEVEL SPACE

MGSPCF:	PUSHJ Q,MGGXPT	; GET XPORT SPACE FORWARD
	TRNE J,600000
	 JRST MGERR
MGSPC:	MOVEM W,MGUNIT
	MOVE B,MGRWCD(W)	; GET COMMAND
	ADD B,MTCONO(W)
IFN TM10B,[
	SETZM MIOWD
	DATAO MTS,[MICWA]
]
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD
	PUSHJ Q,MGDCSO
]
	CONO MTC,(B)	; DO IT
	PUSHJ Q,MGWTJD
	 JRST MGERR	; NO RETRIES
	TRNN J,10000	; EOF
	 SETZB B,MGEOFR(W)
	TRNE J,10000
	 AOS B,MGEOFR(W)
	CAIL B,2	;TOO MANY EOF'S
	 JRST MGSPRF
MGCMDR:	SOS MSCMDC(W)	; GENERAL EXIT ROUTINE
	SETOM MGUNIT
	SKIPG MSCMDC(W)
	 POPJ P,	; NO MORE
	MOVE B,MTCONO(W)
	CONO MTC,MNOPIN(B)	; INTERUPT WHEN UNIT READY
	MOVEM W,MGUNIT	; RESTORE UNIT NUMBER
	PUSHJ Q,MGWTJD
	 JRST MGERR
	SETOM MGUNIT
	POPJ Q,		; MORE

MGSPFR:	MOVEI B,MSPFR	; SPACE FOR RECORD
	MOVEM B,MGRWCD(W)
	MOVSI B,%MAMSO
	IORM B,MSRAC(W)	; TAPE MOVEMENT
	JRST MGSPCF

MGSPFF:	MOVSI B,%MAESO
	TDZE B,MSRAC(W)
	 JRST MGCMDR	; EOF ALREADY READ DURING THE READ
	AOS MSCMDC(W)	;SO IT WILL RETURN
	MOVEI B,MSPFR
	MOVEM B,MGRWCD(W)
	PUSHJ Q,MGSPCF
	SKIPE MGEOFR(W)
	 JRST MGCMDR	; EOF READ ON SPACE RECORD. DONE
	MOVEI B,MSPFF
	MOVEM B,MGRWCD(W)
	JRST MGSPCF

MGSPRR:	MOVEI B,MSPRR
	MOVEM B,MGRWCD(W)
	MOVSI B,%MAMSO
	IORM B,MSRAC(W)
	JRST MGSPCR

MGSPCR:	PUSHJ Q,MGGXPT	; SPACE REVERSE
	TRNE J,600000	; ERR
	 JRST MGERR
	TRNE J,100000	; BOT
	 JRST MGCMDR	; THEN DO NOTHING
	MOVEM W,MGUNIT
	MOVE B,MGRWCD(W)
	ADD B,MTCONO(W)
IFN TM10B,[
	SETZM MIOWD
	DATAO MTS,[MICWA]
]
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD
	PUSHJ Q,MGDCSO
]
	CONO MTC,(B)
	PUSHJ Q,MGWTJD
	 JRST MGERR
	TRNE J,10000
	 SOSGE MGEOFR(W)	; ONE LESS EOF
	  SETZM MGEOFR(W)
	JRST MGCMDR

MGSPRF:	MOVEI B,MSPRF	; REVERSE FILE
	MOVEM B,MGRWCD(W)
	MOVSI A,%MAESO	; EOF READ IN FORWARD DIRECTION
	TDNN A,MSRAC(W)
	 JRST MGSPCR
	AOS MSCMDC(W)	; YES DO IT TWICE
	PUSHJ Q,MGSPCR
	MOVSI B,%MAESO
	ANDCAM B,MSRAC(W)	; TURN OFF FLAG
	JRST MGSPCR	; SECOND TIME

MGRWD1:	PUSHJ Q,MGGXPT	; REWIND
	MOVEM W,MGUNIT
	MOVE B,MGRWCD(W)	; GET COMMAND
	ADD B,MTCONO(W)
	CONO MTC,(B)
	PUSHJ Q,MGWTJD	; WAIT
	 JRST MGERR
	SETZM MGEOFR(W)
	MOVSI A,%MAMSO
	ANDCAM A,MSRAC(W)	;CLEAR TAPE MOTION
MGRWD2:	TRNN J,200000	; STILL REWINDING?
	 JRST MGRWD3	; NO
	PUSHJ Q,CPOPJ	; WAIT
	CONI MTS,J
	MOVEM J,MGCMTS(W)
	JRST MGRWD2

MGRWD3:	MOVE T,TIME	;WAIT 1 SECOND MORE
	ADDI T,30.	;THIS IS AN ATTEMPT TO FIX A HARDWARE BUG
	MOVEM T,MGJDTI
MGRWD4:	MOVE T,TIME
	CAML T,MGJDTI
	 JRST [	SETZM MGJDTI
		POPJ Q, ]
	PUSHJ Q,CPOPJ
	JRST MGRWD4

MGRWND:	MOVEI B,MREWND	; NORMAL REWIND
	CAIA
MGRWDM:	 MOVEI B,MRWNDD	; REWIND AND DISMOUNT
	MOVEM B,MGRWCD(W)
	PUSHJ Q,MGRWD1
	MOVSI A,%MAMSO+%MAREW
	ANDCAM A,MSRAC(W)
	JRST MGCMDR

MGSEOT:	PUSHJ Q,MGGXPT	; SKIP TO LOGICAL EOT
	TRNE J,600000
	 JRST MGERR
	MOVEM W,MGUNIT
	TRNE J,100000	; BOT?
	 JRST MGVTCK	; VIRGIN TAPE CHECK
MGNVT:	MOVE B,MTCONO(W)
IFN TM10A,[
	PUSHJ Q,MGDCSO
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD	; ONE RECORD
]
IFN TM10B,	SETZM MIOWD
	CONO MTC,MSPRR(B)	; SPACE REVERSE FIRST
	PUSHJ Q,MGWTJD	; WAIT
	 JRST MGERR
	SETZM MGEOFR(W)
	AOS MGEOFR(W)
MGEOT2:	MOVE B,MTCONO(W)
	CONO MTC,MSPFF(B)	; SKIP FORWARD FILE
	PUSHJ Q,MGWTJD
	 JRST MGERR
	MOVSI B,%MAETR	; EOT CHECK
	TRNE J,4000
	 IORM B,MSRAC(W)	; TELL MP
	MOVE B,MTCONO(W)
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD	; ONE RECORD
]
IFN TM10B,	SETZM MIOWD
	CONO MTC,MSPFR(B)	; SPACE FORWARD RECORD
	PUSHJ Q,MGWTJD
	 JRST MGERR
	MOVSI B,%MAETR	; EOT AGAIN
	TRNE J,4000
	 IORM B,MSRAC(W)	; TELL MP
	TRNN J,10000	; EOF ALSO?
	 JRST MGEOT2	; NO, TRY AGAIN
	MOVE B,MTCONO(W)	; YES, NOW GO BACK OVER LAST
	CONO MTC,MSPRF(B)
	PUSHJ Q,MGWTJD
	 JRST MGERR
	MOVSI B,%MAEOF+%MAETR	; TELL MP,EOF
	IORM B,MSRAC(W)
	JRST MGCMDR

MGVTCK:	MOVE T,TIME
	ADDI T,60.	; TWO SECOND TIME OUT
	MOVEM T,MGEOTT(W)	; EOT TIME
IFN TM10B,[
	SETZM MIOWD
	DATAO MTS,[MICWA]
]
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD
	PUSHJ Q,MGDCSO
]
	MOVE B,MTCONO(W)
	CONO MTC,MREAD(B)	; DO READ, WAIT EITHER FOR JOB DONE OR TIME OUT
MGVTC1:	CONI MTS,J
	MOVEM J,MGCMTS(W)
	TRNE J,100	; J D?
	 JRST MGNVT	; NOT VIRGIN TAPE
	TRNE J,440000
	 JRST MGERR	; ERRORS?
	MOVE T,MGEOTT(W)
	CAMG T,TIME	; TIME UP?
	 JRST MGVT	; YES
	PUSHJ Q,CPOPJ	; WAIT
	JRST MGVTC1

MGVT:	MOVE B,MTCONO(W)
	CONO MTS,31
	CONO MTC,MNOPIN(B)	; NO-OP WAIT FOR JOB DONE
	PUSHJ Q,MGWTJD
	 JFCL		; SEE IF I CARE IF THERE ARE ERRORS
	MOVEI B,MREWND
	MOVEM B,MGRWCD(W)
	PUSHJ Q,MGRWD1	; REWIND
	SETZM MGEOFR(W)
	AOS MGEOFR(W)
	JRST MGCMDR	; RETURN

MGMEOT:	PUSHJ Q,MGGXPT
	TRNE J,600000
	 JRST MGERR
	MOVEM W,MGUNIT
	SKIPE MTCEFW(W)	;HOW MANY EOF WRITTEN?
	 JRST MGMET1
	AOS MSCMDC(W)	; SO WILL RETURN
	AOS MTCEFW(W)
	PUSHJ Q,MGWEOF
MGMET1:	MOVE A,MTCEFW(W)
	SOSLE A
	 JRST MGMET2
	AOS MSCMDC(W)
	AOS MTCEFW(W)
	PUSHJ Q,MGWEOF
MGMET2:	MOVE A,MSRAC(W)
	TLNE A,%MANWT	; BACK OVER LAST?
	 JRST MGMET3	; NO
	AOS MSCMDC(W)	; SO IT WILL RETURN
	PUSHJ Q,MGSPRF
MGMET3:	MOVSI A,%MANWT
	IORM A,MSRAC(W)
	JRST MGCMDR	; DONE

; WRITE EOF
MGWEOF:	PUSHJ Q,MGGXPT
	TRNE J,600010
	 JRST MGERR
	MOVEM W,MGUNIT
	MOVE B,MTCONO(W)
	CONO MTC,MWEOF(B)
	PUSHJ Q,MGWTJD
	 JRST MGERR
	MOVSI A,%MAMSO
	IORM A,MSRAC(W)	; TAPE MOVEMENT
	JRST MGCMDR	; RETURN

MGSTAT:	PUSHJ Q,MGGXPT	; GETS STATUS
	JRST MGCMDR

MGW3IN:	PUSHJ Q,MGGXPT
	TRNE J,600010
	 JRST MGERR
	MOVEM W,MGUNIT
IFN TM10B,[
	SETZM MIOWD
	DATAO MTS,[MICWA]
]
IFN TM10A,[
	MOVE A,[-1,,MGVTC-1]
	MOVEM A,MIOWD
	PUSHJ Q,MGDCSO
]
	MOVE B,MTCONO(W)
	CONO MTC,MW3IN(B)	; WRITE THE RANDOM WORD PRECEEDED BY 3 INCHES OF BLANK TAPE
	PUSHJ Q,MGWTJD
	 JFCL		; ALLOW BAD TAPE ERROR
	JRST MGSPRR	; NOW SPACE RECORD REVERSE OVER THE ONE WORD

SUBTTL .MTAPE UUO 

;.MTAPE AC,
;	AC/	CHNM,COMMAND
;		COMMAND/	COUNT,,FUNCTION

AMTAPE:	XCTR XR,[HLRZ R,(J)]
	TRNE R,-NIOCHN
	 JRST ILUUO
	HRRZM R,UUAC(U)		; SO THAT ERRORS WILL BE REPORTED ON THE CORRECT CHANNEL
	ADDI R,IOCHNM(U)	; FORM IOCHNM POINTER
	LDB W,[MTXP(R)]	; GET XPORT NUMBER
	CAME U,MTUSR(W)	; SAME USER
	 POPJ P,	; NO
	UMOVE J,(J)
	MOVEM J,MTMTAP(W)	; SAVE J
	HRRZ A,MTMTAP(W)
	PUSHJ P,MTIECK
	UMOVE A,(A)
	HRRZM A,MTMFNC(W)	;STORE FUNCTION
	HLREM A,MTMCNT(W)	;AND COUNT
	SKIPN MTMCNT(W)		;A COUNT OF ZERO ALWAYS MEANS ONE, FOR COMPATIBILITY
	 AOS MTMCNT(W)		; WITH THE OLD CODE.
	HRRZS A
	CAIL A,NMTAPC		; LEGAL COMMAND
	 POPJ P,	; NO
	AOS (P)		; SKIP RETURN
	JRST @MTAPDT(A)

MTAPDT:	MTHANG	;0 HANG TILL TAPE MOTION DONE
	MTRWND	;1 REWIND
	MTRWDM	;2 REWIND AND DISMOUNT
	MTWEOR	;3 WRITE EOR IF APPROPRIATE
	MTW3IN	;4 WRITE 3 INCHES OF BLANK TAPE
	MTWEOF	;5 WRITE EOF
	MTSPR	;6 SPACE RECORDS
	MTSPF	;7 SPACE FILES
	MTSPEOT	;10 SPACE TO EOT
	MTSTOP	;11 STOP ALL COMMAND ASSOCIATED WITH THIS COMMAND
	MTSBKS	;12 SET BLOCK SIZE (TO COUNT)
	MTRBKS	;13 READ BLOCK SIZE (TO AC)
NMTAPC==.-MTAPDT

MTSBKS:	MOVE A,MTMCNT(W)	;DESIRED BLOCKSIZE
	CAIL A,4		;CHECK REASONABLENESS
	 CAILE A,2000
	  SOSA (P)		;FAIL IF TOO BIG OR TOO SMALL
	   MOVEM A,MTBLKS(W)	;OK, CHANGE WRITE-BUFFER SIZE
	POPJ P,

MTRBKS:	MOVE A,MTBLKS(W)
	JRST APTUAJ

MTHANG:	SKIPLE MSCMDC(W)	; HANG UNTILL ALL MOTION FINISHED
	 PUSHJ P,UFLS
	JRST MTIECK

MTRWND:	MOVEI B,MGRWND		; REWIND
MTRWD1:	SKIPE MSCRW(W)
	 JRST MTSOSP
	MOVSI A,%MAREW
	IORM A,MSRAC(W)
	JRST MTCMD

MTRWDM:	MOVEI B,MGRWDM	; REWIND AND DISMOUNT
	JRST MTRWD1

;"WRITE END OF RECORD" - THIS IS REALLY THE FORCE SYSTEM CALL, OR SHOULD BE.
MTWEOR:	SKIPG MTMDN(W)	; ANY BUFFERS STARTED
	 POPJ P,	; NO
	SKIPE MSCRW(W)	; WRITING
	 JRST MTWBFD	; DISCARD BUFFER
MTSOSP:	SOS (P)		; NOT WRITING, ERROR
	POPJ P,

MTWEOF:	SKIPN MSCRW(W)	; WRITING?
	 JRST MTSOSP	; NO
	PUSHJ P,MTWEOR
	MOVEI B,MGWEOF	; WRITE EOF
	AOS MTCEFW(W)
	MOVSI TT,%MANWT
	ANDCAM TT,MSRAC(W)	; SOMETHING WRITTEN
	JRST MTCMD

MTW3IN:	SKIPN MSCRW(W)	; WRITING?
	 JRST MTSOSP
	MOVEI B,MGW3IN
	SETZM MTCEFW(W)
	MOVSI TT,%MANWT
	ANDCAM TT,MSRAC(W)
	JRST MTCMD

;SPACE RECORDS, +=FORWARD, -=BACK
MTSPR:	SKIPE MSCRW(W)	; NOT ALLOWED IF WRITING
	 JRST MTSOSP
	PUSHJ P,MTFLRA	;FLUSH READ-AHEAD, FIND OUT HOW FAR OFF WE ARE
	ADD B,C		;NUMBER OF RECORDS TAPE IS AHEAD OF USER (EOF=RECORD)
	MOVNS B		;SUBTRACT THIS FROM USER'S REQUEST
	ADDB B,MTMCNT(W)
	JUMPE B,CPOPJ	;IF COUNT IS NOW ZERO, WE ARE DONE
MTSPR1:	PUSHJ P,MTCNTR	;UPDATE USER'S COPY IN CASE PCLSR
	JUMPG B,MTSPFR	; SPACE FORWARD
	MOVEI B,MGSPRR	; SPACE REVERSE
	PUSHJ P,MTCMD
	AOSGE B,MTMCNT(W)
	 JRST MTSPR1	;MORE
	POPJ P,

MTSPFR:	MOVEI B,MGSPFR
	PUSHJ P,MTCMD
	SOSLE B,MTMCNT(W)
	 JRST MTSPR1	;MORE
	POPJ P,

;THIS ROUTINE FLUSHES READAHEAD.  CALL BEFORE DOING A SPACING OPERATION
;THIS DOESN'T ACTUALLY UNDO THE EFFECT ON THE DRIVE
;OF THE READ-AHEAD.  IT DOES MAKE SURE THAT READ-AHEAD'S EFFECT CAN'T
;CHANGE, THEN RETURNS IN B THE NUMBER OF RECORDS AHEAD (NON-NEGATIVE)
;AND IN C THE NUMBER OF EOF'S AHEAD (0 OR 1).  IF CALLED TWICE IT WILL
;RETURN ZERO THE SECOND TIME.  BE SURE TO UPDATE YOUR PARAMETERS.
MTFLRA:	PUSHJ P,MTCNTR	;FIRST, ENSURE WRITEABILITY, MUSTN'T PCLSR IN MTCNTR LATER
	MOVSI B,%MASTP
	MOVSI T,%MARAC
	IORM B,MSRAC(W)	;IF READ IS ACTIVE, TELL IT TO STOP
	TDNE T,MSRAC(W)	;AWAIT CESSATION OF READ
	 PUSHJ P,UFLS	;IF THIS PCLSR'S OUT WITH %MASTP SET, NO GREAT HARM DONE.
	ANDCAM B,MSRAC(W)	;THEN TURN OFF %MASTP, THINGS ARE NOW QUIET
	SKIPLE MSCMDC(W)	;BEFORE MESSING WITH BUFFERS, WAIT FOR PI TO QUIESCE
	 PUSHJ P,UFLS
	MOVE B,MSNBOL(W)	;NUMBER OF BUFFERS = NUMBER OF RECORDS
	LDB C,[.BP (%MAEFA),MSRAC(W)] ;1 IF PAST EOF WHICH THE USER DOESN'T KNOW ABOUT
	MOVSI T,%MAEFA		;NOW GET RID OF THE READ-AHEAD
	ANDCAM T,MSRAC(W)
	JRST MTCBFF

MTSPF:	SKIPE MSCRW(W)	; NOT ALLOWED IF WRITING
	 JRST MTSOSP
	PUSHJ P,MTFLRA	;FLUSH READ-AHEAD
	MOVN B,C	;NUMBER OF FILES TAPE IS AHEAD OF USER
	ADDB B,MTMCNT(W)
	JUMPE B,CPOPJ	;DONE
MTSPF1:	PUSHJ P,MTCNTR	;UPDATE USER'S COUNT IN CASE OF PCLSR
	JUMPG B,MTSPFF	; SPACE FORWARD FILES
	MOVEI B,MGSPRF
	PUSHJ P,MTCMD
	AOSGE B,MTMCNT(W)
	 JRST MTSPF1	;MORE
	POPJ P,

MTSPFF:	MOVEI B,MGSPFF
	PUSHJ P,MTCMD
	SOSLE B,MTMCNT(W)
	 JRST MTSPF1	;MORE
	POPJ P,

MTCNTR:	HRRZ A,MTMTAP(W)
	MOVE T,MTMFNC(W)
	HRL T,MTMCNT(W)
	UMOVEM T,(A)
	POPJ P,

MTSTAT:	SKIPLE MSCMDC(W)	; WAIT TILL ALL COMMANDS DONE
	 PUSHJ P,UFLS
	MOVEI B,MGSTAT	; GET CONI'S
	PUSHJ P,MTCMD	; GIVE TO PI
	SKIPLE MSCMDC(W)	; WAIT TILL DONE
	 PUSHJ P,UFLS
	MOVE I,MGCMTC(W)
	MOVE J,MGCMTS(W)
	POPJ P,

MTSPEOT:	MOVEI B,MGSEOT	; SPACE TO LOGICAL EOT
	JRST MTCMD	;NOTE THIS IS INDEPENDENT OF READ-AHEAD

MTSTOP:	CONO PI,UTCOFF	;THIS DOESN'T DEAL WITH READ-AHEAD, PROBABLY OK
	SETZM MSCMDC(W)	;NO MORE COMANDS
	MOVE Q,[-MGQDLL,,MGQD0-1]
	MOVE T,MSLCTB
	IMUL T,W
	ADD Q,T
	MOVEM Q,MGQDLP(W)	; RESTORE Q
	MOVE Q,[-MSCBL-1,,MSCB0-1]
	ADD Q,T
	MOVEM Q,MTCMBP(W)	; INITIALIZE MP AND PI COMAND POINTERS
	MOVE Q,[4400,,MSCB0-1]
	ADD Q,T
	MOVEM Q,MGCMBP(W)
	SKIPL A,MTMDN(W)
	 PUSHJ P,IMEMR	; RELEASE MP BUFFER
	SETOM MTMDN(W)
	SETZM MSMPRP(W)
	SETZM MSMPRC(W)	; SO BLKT WON'T GET UNHAPPY
	PUSHJ P,MTCBFF	; FLUSH BUFFER LIST
	CAME W,MGUNIT	; SAME UNIT?
	 JRST UTCONJ
	SETOM MGUNIT	; SO INTERUPT WILL GO AWAY
	CONI MTC,I	; SEE WHAT DRIVE IS BEING TALKED TO
	LDB B,[MUNITF,,I]
	CAME W,B
	 JRST UTCONJ	; IF NOT SAME UNIT, DON'T DO ANYTHING
	MOVE B,MTCONO(W)
	CONO MTS,31	; STOP THE TAPE
	CONO MTC,(B)	; CLEAR INTERUPTS
	SKIPGE A,MGCABN(W)	; ANY BUFFERS ACTIVE AT PI
	 JRST UTCONJ	; NO
	PUSHJ P,IMEMR	; RETURN IT
	SETOM MGCABN(W)
	JRST UTCONJ

SUBTTL MAG TAPE CLOSE ROUTINES

MTOCL:	LDB W,[MTXP(R)]
	SOSL MTUSE(W)
	 POPJ P,	; NOT ONLY CHANNEL OPEN
	AOS MTUSE(W)	; INCASE PCLSRED
	MOVSI A,%MAERR	;ERROR?
	TDNE A,MSRAC(W)
	 PUSHJ P,MTOCL3
;	MOVEI T,MSCBL-4
;	CAMG T,MSCMDC(W)
;	 PUSHJ P,UFLS	; WAIT FOR ROOM FOR THREE COMMANDS
	SKIPL MTMDN(W)	; MAG TAPE OUTPUT CLOSE
	 PUSHJ P,MTWBFD	; WRITE OUT BUFFERS
;	MOVEI B,MGWEOF	; WRITE OUT TWO EOF(S)
;	SKIPE MTCEFW(W)
;	 JRST MTOCL2	; MAY HAVE BEEN PCLSRED
;MTOCL1:	PUSHJ P,MTCMD
;	AOS MTCEFW(W)	; ONE MORE CLOSE EOF WRITTEN
;MTOCL2:	MOVE A,MTCEFW(W)
;	SOSG A	; DON'T WRITE EOF IF PCLSRED
;	 PUSHJ P,MTCMD	; DO IT TWICE
;	SKIPG A
;	 AOS MTCEFW(W)
;	MOVEI B,MGSPRF
;	MOVE A,MSRAC(W)
;	TLNN A,1000
;	 PUSHJ P,MTCMD	; NOW BACK UP OVER ONE
;	MOVSI A,1000
;	IORM A,MSRAC(W)
	MOVEI B,MGMEOT	; MAKE EOT
	PUSHJ P,MTCMD
	SKIPLE MSCMDC(W)	; NOW WAIT TILL DONE
	 PUSHJ P,UFLS
	MOVEI A,1
	MOVEM A,MGEOFR(W)
	SKIPL MTMDN(W)	;ANY ACTIVE BUFFERS
	 JRST 4,.
	SKIPL MGCABN(W)
	 JRST 4,.
	SKIPE MSNBOL(W)
	 JRST 4,.
	SETOM MTUSR(W)
	SETOM MTUSE(W)
	SETZM MSRAC(W)
	POPJ P,

MTOCL3:	SKIPL A,MTMDN(W)
	 PUSHJ P,MEMR	; IF BUFFER AROUND,FLUSH IT
	SETOM MTMDN(W)
	SETZM MSMPRC(W)
	POPJ P,

MTICL:	LDB W,[MTXP(R)]
	SOSL MTUSE(W)	; LAST USER
	 POPJ P,
	AOS MTUSE(W)
	MOVEI T,1
	CAMGE T,MSCMDC(W)	; ALLOW ONE COMMAND IF REWINDING
	 PUSHJ P,UFLS	; ALL COMMANDS DONE
	MOVE T,MSRAC(W)
	TLNE T,%MAREW	; REWINDING?
	 JRST MTICL3	; YES
	SKIPLE MSCMDC(W)	; NO, WAIT TILL COMMAND DONE
	 PUSHJ P,UFLS
MTICL3:	SKIPL MGCABN(W)	; ANY PI BUFFERS LEFT
	 JRST 4,.
	PUSHJ P,MTRBD	;GET RID OF M.P. BUF, IF ANY
	SETOM MTUSR(W)
	PUSHJ P,MTCBFF	; FREE BUFFERS
	SOS MTUSE(W)
	MOVE T,MSRAC(W)
	TLNE T,%MAREW	; DON'T HAVE TO SKIP TO EOF IF REWINDING
	 JRST MTICL2
	MOVSI A,20
	TDNE A,(R)	;CHECK TO SKIP TO EOF
	 JRST MTICL2
	MOVSI A,%MAMSO
	TDNN A,MSRAC(W)	;TAPE MOVEMENT
	 JRST MTICL2	; NO
	SKIPE MGEOFR(W)	;NO TIMING CONFLECT HERE SINCE WE WAITED FOR PI TO CLEAR
	 JRST MTICL2	;NOTE THAT THIS DISPOSES OF A READ-AHEAD EOF.
	PUSHJ P,MTSTAT
	MOVE B,MGCMTS(W)
	TRNE B,100000
	 JRST MTICL2
	MOVEI B,MGSPFF
	PUSHJ P,MTCMD
	SKIPLE MSCMDC(W)
	 PUSHJ P,UFLS
MTICL2:	MOVSI T,%MAREW
	ANDM T,MSRAC(W)	;CLEAR ALL BUT REWINDING
	POPJ P,		; NO, DONE

MTCBFF:	SKIPN MSNBOL(W)	;ANY BUFFERS ON CHAIN?
	 POPJ P,
	HRRZ A,MSBUFP(W)	;YES, FREE ONE
	PUSHJ P,MTICL1	; FIX CHAIN
	PUSHJ P,MEMR	; RETURN BUFFER
	SOSLE MSNBOL(W)	;ANY MORE?
	 JRST MTCBFF
	SETZM MSBUFP(W)	;EMPTY LIST
	POPJ P,

MTICL1:	LDB T,[MLO,,MEMBLT(A)]	; GET BACK POINTER
	HRRM T,MSBUFP(W)
	POPJ P,
